package robot;

import gui.Client;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.HashMap;
import javax.swing.DefaultListModel;
import threads.QueueClient;

public class DBComm {

    private static Connection conn;
    private static Statement stmnt;
    private static boolean builtID = false;
    private static boolean displayedConnectError = false;

    public static boolean isConnected() {
        return (conn != null);
    }

    public DBComm() {
    }

    public static void connect() {
        try {
            String address = Client.txtAddress.getText();
            String database = Client.txtDatabase.getText();
            String username = Client.txtUsername.getText();
            char[] password = Client.txtPassword.getPassword();

            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://" + address.replaceAll("/", "") + "/" + database, username, getPassword(password));
            System.out.println("Connected to database!");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static String buildID() {
        String id = "";
        int j;
        for (int i = 0; i < 10; i++) {
            id += (char) ((int) (Math.random() * 25 + 65)); //65 - 90 because capital letters
        }
        try {
            int i = 0;
            while (conn == null) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ex) {
                }
            }
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            while (stmnt == null) {
            }
            stmnt.executeUpdate("insert into queue (id, position, timestamp) values('" + id + "', '0', NULL);");
            builtID = true;
        } catch (SQLException ex) {
            ex.printStackTrace();
        }

        return id;
    }

    public static void updateID() {
        try {
            ResultSet rs = null;
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            while (rs == null) {
                rs = stmnt.executeQuery("select position from queue where id ='" + QueueClient.id + "';");
            }
            if (rs.next()) {
                while (builtID == false) {
                }
                if (QueueClient.position != rs.getInt(1)) {
                    QueueClient.position = rs.getInt(1);
                }
            }
            if (QueueClient.position == 0 && (displayedConnectError == false)) {
                Client.updateOutput("It would appear as though the host application is not responding or is not running!");
                displayedConnectError = true;
            } else if (QueueClient.position > 0) {
                displayedConnectError = false;
            }
            stmnt.executeUpdate("update queue set timestamp=now() where id='" + QueueClient.id + "';");
            rs.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static String getPassword(char[] pass) {
        String p = "";
        for (int i = 0; i < pass.length; i++) {
            p += pass[i];
        }
        return p;
    }

    public static Image getVideoFrame() {
        try {
            ResultSet rs = null;
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            byte[] imageBytes = null;
            rs = stmnt.executeQuery("select frame from video where name='frame';");
            if (rs != null) {
                ResultSetMetaData rsmd = rs.getMetaData();
                int row = rsmd.getColumnCount();
                if (row > 0) {
                    rs.absolute(row);
                    imageBytes = rs.getBytes(row);
                }
                Image image = null;
                if (imageBytes != null) {
                    image = Toolkit.getDefaultToolkit().createImage(imageBytes);
                    return image;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static int[] read(String robotID) {
        try {
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            ResultSet rs = stmnt.executeQuery("select * from host_to_applet where robot_id='" + robotID + "';");
            if (rs.next()) {
                int[] data = new int[]{rs.getString(2).charAt(0), rs.getInt(3), rs.getInt(4), rs.getInt(5), rs.getInt(6), rs.getInt(7)};
                stmnt.execute("delete from host_to_applet where robot_id='" + robotID + "';");
                rs.close();
                return data;
            } else {
                rs.close();
                return null;
            }
        } catch (SQLException ex) {
            return null;
        }
    }

    public static void write(String robotID, char heading) {
        try {
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            stmnt.execute("insert into applet_to_host values ('" + robotID + "', '" + heading + "');");
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static int getRobotCount() {
        try {
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            ResultSet rs = stmnt.executeQuery("select count(*) from host_to_applet");
            if (rs.next()) {
                int count = rs.getInt(1);
                rs.close();
                return count;
            } else {
                rs.close();
                return 0;
            }
        } catch (SQLException ex) {
            return 0;
        }
    }

    public static void setSharedVision() throws IOException {
        try {
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            stmnt.execute("delete from sharedvision");
            stmnt.execute("insert into sharedvision values ('" + objectToString((DefaultListModel) Client.lstPhysicalRobots.getModel()) + "', '" + objectToString(criep.CRIEP.PhysicalArena.robotMap) + "');");
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void getSharedVision() {
        try {
            if (!conn.isClosed()) {
                stmnt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
            }
            DefaultListModel dl = new DefaultListModel();
            ResultSet rs = stmnt.executeQuery("select * from sharedvision");
            if (rs.next()) {
                dl = (DefaultListModel) objectFromString(rs.getString(1));
                Client.lstPhysicalRobots.setModel(dl);
                criep.CRIEP.PhysicalArena.robotMap = (HashMap<String, Robot>) objectFromString(rs.getString(1));
                criep.CRIEP.PhysicalArena.getGrid().repaint();
                rs.close();
            }
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } catch (SQLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void disconnect() {
        try {
            if (!conn.isClosed()) {
                stmnt.close();
                conn.close();
            }
        } catch (Exception ex) {
        }
    }

    private static String objectToString(Object o) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(o);
        oos.close();
        return new String(Base64Coder.encode(baos.toByteArray()));
    }

    private static Object objectFromString(String s) throws IOException, ClassNotFoundException {
        byte[] data = Base64Coder.decode(s);
        ObjectInputStream ois = new ObjectInputStream(
                new ByteArrayInputStream(data));
        Object o = ois.readObject();
        ois.close();
        return o;
    }
}
